<template>
  <div id="modern-dashboard">
    <header class="dashboard-header">
      <div class="header-left">
        <div class="system-time">{{ currentSystemTime }}</div>
      </div>
      <div class="header-right">
        <div class="update-info">
          <span>上次更新: <span class="info-value">{{ lastUpdateTime }}</span></span>
          <span class="countdown-text">下次更新: <span class="info-value countdown-value">{{ nextUpdateCountdownDisplay
          }}</span></span>
        </div>
        <div class="auto-update-toggle">
          <label class="switch">
            <input type="checkbox" v-model="isAutoUpdateEnabled" />
            <span class="slider round"></span>
          </label>
          <span>自动更新</span>
        </div>
      </div>
    </header>

    <main class="dashboard-main">
      <section class="left-panel">
        <div class="panel-card chart-card">
          <h2 class="card-title">负荷预测趋势 <span class="title-sub">未来24H预测与历史负荷</span></h2>
          <div v-if="isLoading" class="loading-overlay">
            <div class="loading-spinner"></div>
            <p>数据加载中...</p>
          </div>
          <div class="chart-container" :class="{ 'hidden-chart': isLoading }">
            <v-chart class="chart" :option="mainChartOption" autoresize
              @instance-created="instance => mainChartInstance.value = instance" style="width: 100%; height: 400px;" />
          </div>
        </div>

        <div class="panel-card metrics-card">
          <h2 class="card-title">关键指标速览</h2>
          <div class="metrics-grid">
            <div v-for="(metric, index) in keyMetrics" :key="metric.label" class="metric-item">
              <div class="metric-value" :class="{ 'value-flashing': metric.flashing }">
                <span>{{ metric.displayValue }}</span>
                <span class="metric-unit">{{ metric.unit }}</span>
              </div>
              <div class="metric-label">{{ metric.label }}</div>
            </div>
          </div>
        </div>
      </section>

      <section class="right-panel">
        <div class="panel-card alerts-card">
          <h2 class="card-title">智能预警中心</h2>
          <div class="alerts-list">
            <TransitionGroup name="alert-fade">
              <div v-if="alerts.length === 0 && !isLoading" key="no-alerts" class="no-alerts">
                <i class="icon-check"></i> 当前无负荷异常预警
              </div>
              <div v-else v-for="(alert, index) in alerts" :key="alert.id" :class="['alert-item', alert.level]">
                <i :class="['alert-icon', getAlertIconClass(alert.level)]"></i>
                <span class="alert-message">{{ alert.message }}</span>
                <span class="alert-time">{{ alert.time }}</span>
              </div>
            </TransitionGroup>
          </div>
        </div>

        <div class="panel-card trend-card">
          <h2 class="card-title">未来7日负荷峰值预测</h2>
          <div class="chart-container">
            <v-chart class="chart" :option="sevenDayTrendOption" autoresize />
          </div>
        </div>

        <div class="panel-card control-card">
          <h2 class="card-title">数据控制台</h2>
          <div class="control-group">
            <label for="area-select" class="control-label">选择区域:</label>
            <div class="custom-select">
              <select id="area-select" v-model="selectedArea">
                <option value="all">所有区域</option>
                <option value="regionA">区域 A</option>
                <option value="regionB">区域 B</option>
                <option value="regionC">区域 C</option>
              </select>
              <span class="select-arrow"></span>
            </div>
          </div>
          <button class="manual-update-btn" @click="fetchData(true)">手动刷新数据</button>
        </div>
      </section>
    </main>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, computed, watch, nextTick } from 'vue';
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { LineChart, BarChart } from 'echarts/charts';
import {
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  MarkLineComponent,
  MarkPointComponent,
  ToolboxComponent,
  DataZoomComponent
} from 'echarts/components';
import VChart from 'vue-echarts';
import dayjs from 'dayjs';

// ECharts 按需引入
use([
  CanvasRenderer,
  LineChart,
  BarChart,
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  MarkLineComponent,
  MarkPointComponent,
  ToolboxComponent,
  DataZoomComponent
]);

// 添加ECharts实例引用
const mainChartInstance = ref(null);

// --- 模拟数据和状态管理 ---
const UPDATE_INTERVAL = 8 * 1000; // 演示用8秒更新，兼顾视觉效果和数据变化感
let dataTimer = null;
let clockTimer = null;
let countdownTimer = null;

const currentSystemTime = ref(dayjs().format('YYYY-MM-DD HH:mm:ss'));
const lastUpdateTime = ref('--:--:--');
const nextUpdateCountdown = ref(UPDATE_INTERVAL / 1000);
const isLoading = ref(false); // 新增加载状态

const nextUpdateCountdownDisplay = computed(() => {
  return typeof nextUpdateCountdown.value === 'number' ? `${nextUpdateCountdown.value}s` : nextUpdateCountdown.value;
});

// (一) 核心图表数据
const actualLoadData = ref([]);
const predictedLoadData = ref([]);
const deviationPoints = ref([]); // 用于标记图表上的异常点

// (二) 关键指标
const keyMetrics = ref([
  { value: 342.5, displayValue: '342.5', unit: 'kW', label: '当前 (14:30) 实际负荷', flashing: false },
  { value: 458.2, displayValue: '458.2', unit: 'kW', label: '未来24H预测峰值 (18:45)', flashing: false },
  { value: 287.1, displayValue: '287.1', unit: 'kW', label: '未来24H预测谷值 (03:15)', flashing: false },
  { value: 96.8, displayValue: '96.8', unit: '%', label: '近24H预测准确率 (MAPE)', flashing: false }
]);

// (四) 预警信息
let alertIdCounter = 0;
const alerts = ref([]);

// (五) 控制区
const selectedArea = ref('all');
const isAutoUpdateEnabled = ref(true);

// --- 数据模拟函数 ---
const generateDailyPattern = (base, dayOffset = 0, randomness = 1, hourOffset = 0) => {
  const pattern = [];
  const pointsPerDay = 96; // 24 hours * 4 points/hour (every 15 minutes)
  const baseTime = dayjs().startOf('day').add(dayOffset, 'day');

  for (let i = 0; i < pointsPerDay; i++) {
    const timeInMinutes = (i * 15 + hourOffset * 60) % (24 * 60); // 确保小时数在0-24小时循环
    const hour = Math.floor(timeInMinutes / 60);
    const minute = timeInMinutes % 60;

    // 使用更复杂的函数模拟负荷变化，包含日间高峰和夜间低谷
    const phase1 = Math.sin(i / pointsPerDay * Math.PI * 2 + Math.PI / 2); // 模拟日间高峰
    const phase2 = Math.sin(i / pointsPerDay * Math.PI * 4); // 模拟更细微的波动

    let load = base * (0.8 + 0.4 * phase1); // 基础波动
    load += (Math.random() * 2 - 1) * 30 * randomness; // 增加更多的随机噪声，使其“跳动”更明显

    if (hour > 8 && hour < 12) load += 50 * (Math.random() * 0.5 + 0.5); // 上午高峰
    if (hour > 18 && hour < 22) load += 70 * (Math.random() * 0.5 + 0.5); // 晚高峰
    if (hour < 6 || hour > 23) load -= 80 * (Math.random() * 0.5 + 0.5); // 夜间低谷

    const timestamp = baseTime.add(hour, 'hour').add(minute, 'minute').valueOf();
    pattern.push([timestamp, Math.max(50, load)]); // 确保负荷不低于某个值
  }
  return pattern;
};

// 核心数据获取函数
const fetchData = async (isManual = false) => {
  if (isLoading.value) return;

  isLoading.value = true;
  console.log('Fetching new data...');

  try {
    const response = await fetch('classification_96_samples.json');
    if (!response.ok) throw new Error(`HTTP错误: ${response.status}`);

    const jsonData = await response.json();
    console.log('原始JSON数据:', jsonData);

    // 匹配JSON文件的字段
    // classification_96_samples.json 是数组，每个元素有 features.value、actual_weather_status、predicted_weather_status
    const time_points = jsonData.map((item, idx) => {
      // 按15分钟间隔生成时间点
      const hour = Math.floor(idx * 15 / 60).toString().padStart(2, '0');
      const minute = (idx * 15 % 60).toString().padStart(2, '0');
      return `${hour}:${minute}`;
    });
    const actual_values = jsonData.map(item => Number(item.actual_weather_status));
    const predicted_values = jsonData.map(item => Number(item.predicted_weather_status));

    // 验证数据完整性
    if (!actual_values || !predicted_values || !time_points) {
      throw new Error('JSON缺少必要字段');
    }
    if (actual_values.length !== time_points.length || predicted_values.length !== time_points.length) {
      throw new Error(`数组长度不匹配: actual=${actual_values.length}, predicted=${predicted_values.length}, time_points=${time_points.length}`);
    }

    // 转换时间戳并验证
    const today = dayjs().startOf('day');
    const newActualData = [];
    const newPredictedData = [];
    for (let i = 0; i < time_points.length; i++) {
      // 拼接日期和时间，格式如 "2025-07-15 00:00"
      const ts = dayjs(`${today.format('YYYY-MM-DD')} ${time_points[i]}`, 'YYYY-MM-DD HH:mm');
      if (!ts.isValid()) {
        console.error(`无效时间戳格式: ${time_points[i]}`);
        continue;
      }
      newActualData.push([ts.valueOf(), actual_values[i]]);
      newPredictedData.push([ts.valueOf(), predicted_values[i]]);
    }

    console.log('转换后的数据:', { newActualData, newPredictedData });

    actualLoadData.value = newActualData;
    predictedLoadData.value = newPredictedData;

    // 手动触发ECharts更新
    nextTick(() => {
      if (mainChartInstance) {
        mainChartInstance.resize();
        mainChartInstance.setOption(mainChartOption.value);
      }
    });

    updateKeyMetrics();
    checkForAlerts();
    lastUpdateTime.value = dayjs().format('HH:mm:ss');

  } catch (error) {
    console.error('数据加载失败:', error);
    alerts.value.push({
      id: alertIdCounter++,
      level: 'error',
      message: `数据加载失败: ${error.message}`,
      time: dayjs().format('HH:mm:ss')
    });
  }

  if (isAutoUpdateEnabled.value) {
    nextUpdateCountdown.value = UPDATE_INTERVAL / 1000;
  }
  isLoading.value = false;
};

// --- 关键指标更新逻辑 ---
const updateKeyMetrics = () => {
  const oldMetricValues = keyMetrics.value.map(m => m.value); // 存储旧值用于比较

  // 当前负荷：从实际负荷的最后一个点获取
  const currentPoint = actualLoadData.value[actualLoadData.value.length - 1];
  let newCurrentLoad = currentPoint ? parseFloat(currentPoint[1]).toFixed(1) : '--';
  keyMetrics.value[0].value = parseFloat(newCurrentLoad);
  keyMetrics.value[0].label = `当前 (${dayjs(currentPoint[0]).format('HH:mm')}) 实际负荷`;

  // 预测峰谷值
  if (predictedLoadData.value.length > 1) {
    const futurePoints = predictedLoadData.value.slice(1); // 排除与实际数据重合的第一个点
    if (futurePoints.length > 0) {
      const peak = futurePoints.reduce((max, p) => parseFloat(p[1]) > parseFloat(max[1]) ? p : max, futurePoints[0]);
      const trough = futurePoints.reduce((min, p) => parseFloat(p[1]) < parseFloat(min[1]) ? p : min, futurePoints[0]);

      keyMetrics.value[1].value = parseFloat(peak[1]).toFixed(1);
      keyMetrics.value[1].label = `未来24H预测峰值 (${dayjs(peak[0]).format('HH:mm')})`;

      keyMetrics.value[2].value = parseFloat(trough[1]).toFixed(1);
      keyMetrics.value[2].label = `未来24H预测谷值 (${dayjs(trough[0]).format('HH:mm')})`;
    }
  }

  // 预测准确率 (MAPE) - 随机小幅波动，模拟更动态的变化
  let currentMAPE = keyMetrics.value[3].value;
  let newMAPE = (currentMAPE + (Math.random() * 2 - 1) * 0.8); // 波动范围增大
  newMAPE = Math.max(90.0, Math.min(99.9, newMAPE)); // 限制范围
  keyMetrics.value[3].value = parseFloat(newMAPE.toFixed(2));

  // 更新 displayValue 并触发闪烁动画
  keyMetrics.value.forEach((metric, index) => {
    const oldValue = oldMetricValues[index];
    const newValue = metric.value;

    if (newValue !== undefined && newValue !== null) {
      metric.displayValue = parseFloat(newValue).toFixed(metric.unit === '%' ? 2 : 1);
    } else {
      metric.displayValue = '--';
    }

    if (oldValue !== undefined && Math.abs(parseFloat(newValue) - parseFloat(oldValue)) > 0.1) { // 阈值判断
      metric.flashing = true;
      // 动画结束后移除flashing状态
      setTimeout(() => {
        metric.flashing = false;
      }, 700); // 配合 CSS 动画时长
    }
  });
};

const checkForAlerts = () => {
  const newAlerts = [];
  deviationPoints.value = [];

  // 模拟负荷骤增预警
  const now = dayjs();
  const oneHourLater = now.add(1, 'hour');
  const currentLoadVal = parseFloat(keyMetrics.value[0].value);
  const futurePointsInHour = predictedLoadData.value.filter(p => dayjs(p[0]).isAfter(now) && dayjs(p[0]).isBefore(oneHourLater));

  if (futurePointsInHour.length > 0 && !isNaN(currentLoadVal) && currentLoadVal > 0) {
    const maxInHour = Math.max(...futurePointsInHour.map(p => parseFloat(p[1])));
    const increasePercent = ((maxInHour - currentLoadVal) / currentLoadVal) * 100;
    if (increasePercent > 35 + Math.random() * 15) { // 更高的随机阈值
      newAlerts.push({
        id: alertIdCounter++,
        level: 'warning',
        message: `[${dayjs(now).format('HH:mm')}] 预警: 未来1小时负荷预计骤增 ${increasePercent.toFixed(0)}%`,
        time: dayjs().format('HH:mm:ss')
      });
    }
  }

  // 模拟历史偏差过大（随机出现）
  if (Math.random() < 0.25 && actualLoadData.value.length > 10) { // 25%概率出现
    const checkPointIndex = Math.floor(Math.random() * (actualLoadData.value.length - 5)); // 随机选一个历史点
    const checkPoint = actualLoadData.value[checkPointIndex];
    if (checkPoint) {
      const simulatedOldPrediction = parseFloat(checkPoint[1]) * (1 + (Math.random() > 0.5 ? 1 : -1) * (0.08 + Math.random() * 0.07)); // 8%-15%偏差
      const deviation = Math.abs((parseFloat(checkPoint[1]) - simulatedOldPrediction) / simulatedOldPrediction);

      if (deviation > 0.10) { // 大于10%偏差
        newAlerts.push({
          id: alertIdCounter++,
          level: 'error',
          message: `[${dayjs(checkPoint[0]).format('HH:mm')}] 偏差: 历史负荷与预测偏差超${(deviation * 100).toFixed(0)}%`,
          time: dayjs().format('HH:mm:ss')
        });
        deviationPoints.value.push({
          name: '偏差点',
          coord: checkPoint,
          value: parseFloat(checkPoint[1]).toFixed(0),
          itemStyle: { color: '#FF6347' }, // 使用橙红色
          label: {
            formatter: '{c}kW\n偏差 ${(deviation * 100).toFixed(0)}%',
            color: '#fff',
            backgroundColor: 'rgba(255, 99, 71, 0.8)',
            padding: [4, 6],
            borderRadius: 4
          }
        });
      }
    }
  }

  // 模拟警报解决（随机移除旧警报）
  const alertsToRemove = [];
  if (alerts.value.length > 0 && Math.random() < 0.3) { // 30%概率移除一个
    const randomIndex = Math.floor(Math.random() * alerts.value.length);
    alertsToRemove.push(alerts.value[randomIndex].id);
    newAlerts.push({
      id: alertIdCounter++,
      level: 'info',
      message: `[${dayjs().format('HH:mm')}] 通知: 某个负荷异常预警已解除。`,
      time: dayjs().format('HH:mm:ss')
    });
  }

  // 合并新旧警报，并移除已解决的
  let updatedAlerts = [...alerts.value.filter(a => !alertsToRemove.includes(a.id)), ...newAlerts];
  // 保持警报数量在一个合理范围，例如最多5-7个，超出则移除最旧的
  if (updatedAlerts.length > 7) {
    updatedAlerts = updatedAlerts.slice(updatedAlerts.length - 7);
  }
  alerts.value = updatedAlerts.sort((a, b) => b.id - a.id); // 按ID降序，最新的在上面
};


const getAlertIconClass = (level) => {
  switch (level) {
    case 'warning': return 'icon-warning';
    case 'error': return 'icon-error';
    case 'info': return 'icon-info';
    default: return 'icon-info';
  }
};


// --- ECharts 配置 ---
const mainChartOption = computed(() => ({
  backgroundColor: '#fff', // 白色背景
  grid: {
    top: '15%',
    right: '5%',
    bottom: '20%',
    left: '8%'
  },
  tooltip: {
    trigger: 'axis',
    backgroundColor: 'rgba(255, 255, 255, 0.9)',
    borderColor: '#E0E0E0',
    borderWidth: 1,
    textStyle: {
      color: '#333',
      fontSize: 14
    },
    axisPointer: {
      type: 'cross',
      label: {
        backgroundColor: '#6a7985'
      },
      lineStyle: {
        color: '#ccc', // 浅灰色十字线
        type: 'solid'
      }
    },
    formatter: (params) => {
      const time = dayjs(params[0].value[0]).format('YYYY-MM-DD HH:mm');
      let content = `<div style="font-weight: bold; margin-bottom: 8px; color: #333;">${time}</div>`;
      params.forEach(param => {
        if (param.seriesName !== '当前时间') {
          content += `<div style="margin: 4px 0; display: flex; align-items: center; gap: 8px;">
            <span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
            <span style="color: #666;">${param.seriesName}:</span>
            <span style="color: #333; font-weight: bold;">${param.value[1]}</span>
            <span style="color: #888;">kW</span>
          </div>`;
        }
      });
      return content;
    }
  },
  xAxis: {
    type: 'time',
    axisLabel: {
      formatter: '{HH}:{mm}',
      color: '#666',
      fontSize: 12
    },
    axisLine: {
      lineStyle: {
        color: '#CCC'
      }
    },
    splitLine: { show: false }
  },
  yAxis: {
    type: 'value',
    name: '负荷 (kW)',
    nameTextStyle: {
      color: '#666',
      fontSize: 14
    },
    axisLabel: {
      color: '#666',
      fontSize: 12
    },
    axisLine: {
      lineStyle: {
        color: '#CCC'
      }
    },
    splitLine: {
      lineStyle: {
        color: '#EEE',
        type: 'dashed'
      }
    }
  },
  legend: {
    data: ['历史实际负荷', '未来24H预测负荷'],
    right: '5%',
    top: '5%',
    textStyle: {
      color: '#333',
      fontSize: 13
    }
  },
  toolbox: {
    show: true,
    feature: {
      dataZoom: {
        yAxisIndex: 'none',
        title: {
          zoom: '区域缩放',
          back: '区域缩放还原'
        }
      },
      dataView: { readOnly: false, title: '数据视图', lang: ['数据视图', '关闭', '刷新'] },
      magicType: { type: ['line', 'bar'], title: { line: '切换为折线图', bar: '切换为柱状图' } },
      restore: { title: '还原' },
      saveAsImage: { title: '保存为图片' }
    },
    top: '5%',
    left: 'left',
    iconStyle: {
      borderColor: '#666'
    },
    emphasis: {
      iconStyle: {
        borderColor: '#409EFF' // Element UI 主色
      }
    }
  },
  dataZoom: [
    {
      type: 'inside',
      xAxisIndex: 0,
      zoomOnMouseWheel: true,
      moveOnMouseMove: true
    },
    {
      type: 'slider',
      xAxisIndex: 0,
      height: 20,
      bottom: '5%',
      textStyle: {
        color: '#666'
      },
      handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z',
      handleSize: '80%',
      handleStyle: {
        color: '#409EFF', // Element UI 主色
        borderColor: '#409EFF'
      },
      fillerColor: 'rgba(64, 158, 255, 0.2)',
      backgroundColor: '#F0F0F0',
      borderColor: 'transparent'
    }
  ],
  series: [
    {
      name: '历史实际负荷',
      type: 'line',
      data: actualLoadData.value,
      smooth: true,
      showSymbol: false,
      lineStyle: {
        width: 2,
        color: '#409EFF' // 蓝色
      },
      areaStyle: {
        color: {
          type: 'linear',
          x: 0,
          y: 0,
          x2: 0,
          y2: 1,
          colorStops: [{
            offset: 0,
            color: 'rgba(64, 158, 255, 0.2)'
          }, {
            offset: 1,
            color: 'rgba(64, 158, 255, 0)'
          }]
        }
      },
      markPoint: {
        symbolSize: 40, // 增大圆点大小
        symbol: 'circle',
        label: {
          show: true,
          formatter: '{c}kW',
          color: '#fff',
          fontSize: 10,
          offset: [0, -15] // 调整位置
        },
        itemStyle: {
          color: '#FF6347', // 橙红色
          shadowBlur: 5,
          shadowColor: 'rgba(255, 99, 71, 0.5)'
        },
        data: deviationPoints.value.map(point => ({
          name: point.name,
          coord: point.coord,
          value: parseFloat(point.coord[1]).toFixed(0),
          itemStyle: point.itemStyle,
          label: point.label
        }))
      }
    },
    {
      name: '未来24H预测负荷',
      type: 'line',
      data: predictedLoadData.value,
      smooth: true,
      showSymbol: false,
      lineStyle: {
        width: 2,
        type: 'solid', // 实线
        color: '#67C23A' // 绿色，与实际负荷区分
      }
    },
    {
      name: '当前时间',
      type: 'line',
      markLine: {
        silent: true,
        symbol: 'none',
        label: {
          formatter: '{b}',
          position: 'end',
          color: '#F56C6C', // 红色
          fontSize: 12
        },
        lineStyle: {
          color: '#F56C6C', // 红色
          width: 2,
          type: 'solid'
        },
        data: [
          {
            name: '当前',
            xAxis: dayjs().valueOf()
          }
        ]
      }
    }
  ],
  animationEasing: 'cubicInOut', // 更平滑的动画效果
  animationDuration: 1200 // 动画时长
}));

// 未来7天趋势图
const sevenDayTrendOption = computed(() => {
  const days = Array.from({ length: 7 }, (_, i) => dayjs().add(i, 'day').format('MM-DD'));
  const peakData = Array.from({ length: 7 }, () => 400 + Math.random() * 150 + (Math.random() * 50 - 25));
  return {
    backgroundColor: '#fff',
    grid: {
      top: '20%',
      right: '5%',
      bottom: '15%',
      left: '15%'
    },
    tooltip: {
      trigger: 'axis',
      backgroundColor: 'rgba(255, 255, 255, 0.9)',
      borderColor: '#E0E0E0',
      textStyle: {
        color: '#333'
      },
      formatter: function (params) {
        const data = params[0];
        return `<div style="color: #333; font-weight: bold;">${data.name}</div>
                <div style="color: #666; margin-top: 4px;">峰值负荷: <span style="color: #409EFF; font-weight: bold;">${data.value.toFixed(0)}</span> kW</div>`;
      }
    },
    xAxis: {
      type: 'category',
      data: days,
      axisLabel: {
        color: '#666',
        fontSize: 11
      },
      axisLine: {
        lineStyle: {
          color: '#CCC'
        }
      }
    },
    yAxis: {
      type: 'value',
      name: 'kW',
      nameTextStyle: {
        color: '#666'
      },
      splitLine: {
        lineStyle: {
          color: '#EEE',
          type: 'dashed'
        }
      },
      axisLabel: {
        color: '#666',
        fontSize: 11
      }
    },
    series: [{
      data: peakData,
      type: 'bar',
      barWidth: '60%',
      itemStyle: {
        color: {
          type: 'linear',
          x: 0,
          y: 0,
          x2: 0,
          y2: 1,
          colorStops: [{
            offset: 0,
            color: '#409EFF' // 蓝色渐变
          }, {
            offset: 1,
            color: '#A0CFFF'
          }]
        },
        shadowColor: 'rgba(64, 158, 255, 0.2)',
        shadowBlur: 5
      }
    }],
    animationEasing: 'cubicOut',
    animationDuration: 1000
  };
});

// --- 生命周期钩子 ---
onMounted(() => {
  fetchData(); // 立即执行一次数据加载

  // 定时更新系统时间
  clockTimer = setInterval(() => {
    currentSystemTime.value = dayjs().format('YYYY-MM-DD HH:mm:ss');
  }, 1000);

  // 定时获取新数据
  dataTimer = setInterval(() => {
    if (isAutoUpdateEnabled.value && !isLoading.value) {
      fetchData();
    }
  }, UPDATE_INTERVAL);

  // 定时更新倒计时
  countdownTimer = setInterval(() => {
    if (isAutoUpdateEnabled.value && typeof nextUpdateCountdown.value === 'number') {
      if (nextUpdateCountdown.value > 0) {
        nextUpdateCountdown.value--;
      } else {
        // 倒计时归零，等待 fetchData 完成后会重置
        nextUpdateCountdown.value = '更新中...';
      }
    }
  }, 1000);
});

onUnmounted(() => {
  clearInterval(dataTimer);
  clearInterval(clockTimer);
  clearInterval(countdownTimer);
});

// 监听筛选变化
watch(selectedArea, (newArea) => {
  console.log(`区域切换到: ${newArea}`);
  // 模拟数据加载，清空当前图表数据，显示 loading
  isLoading.value = true;
  actualLoadData.value = [];
  predictedLoadData.value = [];
  deviationPoints.value = [];
  alerts.value = [];
  setTimeout(() => {
    fetchData(true); // 区域切换时刷新数据，模拟手动刷新
  }, 500); // 模拟加载时间
});

// 监听自动更新开关，重置倒计时
watch(isAutoUpdateEnabled, (newValue) => {
  if (newValue) {
    nextUpdateCountdown.value = UPDATE_INTERVAL / 1000;
    fetchData(); // 立即获取一次数据
  } else {
    nextUpdateCountdown.value = '暂停';
  }
});
</script>

<style>
/* --- 全局样式和变量 --- */
:root {
  --color-bg: #F0F2F5;
  /* 浅灰色背景 */
  --color-card-bg: #FFFFFF;
  /* 卡片白色背景 */
  --color-border: #E0E0E0;
  /* 浅灰色边框 */
  --color-primary: #409EFF;
  /* 主蓝色 */
  --color-primary-light: #66B1FF;
  /* 浅蓝色 */
  --color-success: #67C23A;
  /* 绿色 */
  --color-warning: #E6A23C;
  /* 黄色 */
  --color-danger: #F56C6C;
  /* 红色 */
  --color-info: #909399;
  /* 信息灰色 */
  --color-text-primary: #303133;
  /* 主要文字色 */
  --color-text-secondary: #606266;
  /* 次要文字色 */
  --color-text-placeholder: #C0C4CC;
  /* 占位文字色 */

  --border-radius-base: 8px;
  --box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.1);
  /* 轻微阴影 */
  --box-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.15);
  /* 悬停阴影 */
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Microsoft YaHei", "PingFang SC", sans-serif;
  background-color: var(--color-bg);
  color: var(--color-text-primary);
  overflow: hidden;
  /* 防止主页面滚动条 */
  font-size: 14px;
}

/* --- 仪表盘容器 --- */
#modern-dashboard {
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100%;
  background: var(--color-bg);
  padding: 20px;
  box-sizing: border-box;
  overflow-y: auto;
  /* 允许在内容溢出时主容器滚动 */
  scrollbar-width: thin;
  scrollbar-color: var(--color-primary) var(--color-border);
}

#modern-dashboard::-webkit-scrollbar {
  width: 8px;
}

#modern-dashboard::-webkit-scrollbar-track {
  background: var(--color-bg);
}

#modern-dashboard::-webkit-scrollbar-thumb {
  background-color: var(--color-primary);
  border-radius: 4px;
  border: 2px solid var(--color-bg);
}

/* --- 头部样式 --- */
.dashboard-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 15px 25px;
  background-color: var(--color-card-bg);
  border-radius: var(--border-radius-base);
  box-shadow: var(--box-shadow-base);
  margin-bottom: 20px;
}

.header-left,
.header-right {
  display: flex;
  align-items: center;
  gap: 20px;
}

.system-time {
  font-size: 1.5em;
  font-weight: bold;
  color: var(--color-primary);
}

.update-info {
  font-size: 0.95em;
  color: var(--color-text-secondary);
  display: flex;
  gap: 15px;
}

.info-value {
  font-weight: bold;
  color: var(--color-primary);
}

.countdown-value {
  color: var(--color-danger);
  /* 倒计时用红色 */
}

/* 自动更新开关 */
.auto-update-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.9em;
  color: var(--color-text-secondary);
}

.switch {
  position: relative;
  display: inline-block;
  width: 40px;
  height: 22px;
}

.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 16px;
  width: 16px;
  left: 3px;
  bottom: 3px;
  background-color: white;
  transition: .4s;
}

input:checked+.slider {
  background-color: var(--color-primary);
}

input:focus+.slider {
  box-shadow: 0 0 1px var(--color-primary);
}

input:checked+.slider:before {
  transform: translateX(18px);
}

/* Rounded sliders */
.slider.round {
  border-radius: 22px;
}

.slider.round:before {
  border-radius: 50%;
}


/* --- 主内容区域 --- */
.dashboard-main {
  flex-grow: 1;
  display: grid;
  grid-template-columns: 3fr 1fr;
  /* 左侧更大，右侧较窄 */
  gap: 20px;
  overflow: hidden;
  /* 防止内部内容撑破布局 */
}

/* --- 卡片通用样式 --- */
.panel-card {
  background-color: var(--color-card-bg);
  border-radius: var(--border-radius-base);
  padding: 20px;
  box-shadow: var(--box-shadow-base);
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.panel-card:hover {
  box-shadow: var(--box-shadow-hover);
  transition: box-shadow 0.3s ease;
}

.card-title {
  font-size: 1.4em;
  font-weight: 600;
  color: var(--color-text-primary);
  margin-top: 0;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--color-border);
}

.title-sub {
  font-size: 0.7em;
  color: var(--color-text-secondary);
  font-weight: normal;
  margin-left: 10px;
}

/* Loading 效果 */
.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.8);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 10;
  transition: opacity 0.3s ease;
}

.hidden-chart {
  opacity: 0;
}

.loading-spinner {
  border: 4px solid #f3f3f3;
  border-top: 4px solid var(--color-primary);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  animation: spin 1s linear infinite;
  margin-bottom: 10px;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

/* --- ECharts 容器 --- */
.chart-container {
  flex-grow: 1;
  min-height: 250px;
  transition: opacity 0.3s ease;
}

/* --- 关键指标 --- */
.metrics-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 15px;
  flex-grow: 1;
}

.metric-item {
  background-color: var(--color-card-bg);
  border-radius: var(--border-radius-base);
  padding: 15px;
  text-align: center;
  box-shadow: var(--box-shadow-base);
  transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.metric-item:hover {
  transform: translateY(-3px);
  box-shadow: var(--box-shadow-hover);
}

.metric-value {
  font-size: 2.2em;
  /* 与截图中的大数字保持一致 */
  font-weight: bold;
  color: var(--color-primary);
  /* 使用主蓝色 */
  margin-bottom: 5px;
  transition: color 0.3s ease-out;
  /* 颜色变化过渡 */
}

.metric-unit {
  font-size: 0.6em;
  vertical-align: super;
  margin-left: 5px;
  color: var(--color-text-secondary);
}

.metric-label {
  font-size: 0.9em;
  color: var(--color-text-secondary);
}

/* 关键指标值闪烁动画 */
.metric-value.value-flashing {
  animation: value-flash 0.7s ease-out forwards;
}

@keyframes value-flash {
  0% {
    color: var(--color-danger);
    transform: scale(1);
  }

  /* 变化时闪烁红色 */
  50% {
    color: var(--color-danger);
    transform: scale(1.05);
  }

  100% {
    color: var(--color-primary);
    transform: scale(1);
  }

  /* 恢复正常色 */
}

/* --- 预警信息 --- */
.alerts-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex-grow: 1;
  overflow-y: auto;
  padding-right: 5px;
  scrollbar-width: thin;
  scrollbar-color: var(--color-primary) var(--color-bg);
}

.alerts-list::-webkit-scrollbar {
  width: 6px;
}

.alerts-list::-webkit-scrollbar-track {
  background: var(--color-bg);
}

.alerts-list::-webkit-scrollbar-thumb {
  background-color: var(--color-primary);
  border-radius: 3px;
  border: 1px solid var(--color-bg);
}

.no-alerts {
  color: var(--color-success);
  font-size: 1em;
  text-align: center;
  padding: 20px;
  border: 1px dashed var(--color-border);
  border-radius: var(--border-radius-base);
  margin-top: auto;
  margin-bottom: auto;
  opacity: 0.7;
}

.alert-item {
  display: flex;
  align-items: center;
  padding: 10px 15px;
  border-radius: var(--border-radius-base);
  font-size: 0.9em;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
  position: relative;
  /* for TransitionGroup absolute positioning */
}

.alert-item.warning {
  background-color: #FFFBE6;
  /* 浅黄色 */
  border: 1px solid var(--color-warning);
  color: var(--color-warning);
}

.alert-item.error {
  background-color: #FEF0F0;
  /* 浅红色 */
  border: 1px solid var(--color-danger);
  color: var(--color-danger);
}

.alert-item.info {
  background-color: #EDF2FA;
  /* 浅蓝色 */
  border: 1px solid var(--color-primary);
  color: var(--color-text-secondary);
}

.alert-icon {
  display: inline-block;
  width: 1.2em;
  height: 1.2em;
  vertical-align: middle;
  margin-right: 8px;
  background-color: currentColor;
  /* 使用父元素的文本颜色 */
}

/* Icons using mask technique (simplified for common ones) */
.icon-check {
  mask: url('data:image/svg+xml;charset=UTF-8,%3Csvg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M4 12.6111L8.92308 17.5L20 6.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3C/path%3E%3C/svg%3E') no-repeat center / contain;
}

.icon-warning {
  mask: url('data:image/svg+xml;charset=UTF-8,%3Csvg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M12 9V13M12 17H12.01M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3C/path%3E%3C/svg%3E') no-repeat center / contain;
}

.icon-error {
  mask: url('data:image/svg+xml;charset=UTF-8,%3Csvg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M18 6L6 18M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3C/path%3E%3C/svg%3E') no-repeat center / contain;
}

.icon-info {
  mask: url('data:image/svg+xml;charset=UTF-8,%3Csvg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M12 17H12.01M12 12V8M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3C/path%3E%3C/svg%3E') no-repeat center / contain;
}

/* Webkit mask for Safari */
.icon-check,
.icon-warning,
.icon-error,
.icon-info {
  -webkit-mask: inherit;
}

.alert-message {
  flex-grow: 1;
}

.alert-time {
  font-size: 0.8em;
  color: var(--color-text-placeholder);
  margin-left: 10px;
  flex-shrink: 0;
}

/* 预警列表进入/离开动画 */
.alert-fade-enter-active,
.alert-fade-leave-active {
  transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
}

.alert-fade-enter-from,
.alert-fade-leave-to {
  opacity: 0;
  transform: translateX(20px);
}

.alert-fade-leave-active {
  position: absolute;
  /* 防止列表元素在离开时瞬间占据空间导致抖动 */
  width: calc(100% - 30px);
  /* 减去padding */
}


/* --- 控制区 --- */
.control-group {
  display: flex;
  align-items: center;
  gap: 15px;
  margin-bottom: 15px;
}

.control-label {
  color: var(--color-text-primary);
  font-size: 1em;
  flex-shrink: 0;
}

.custom-select {
  position: relative;
  display: inline-block;
  flex-grow: 1;
}

.custom-select select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-color: var(--color-card-bg);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 8px 30px 8px 12px;
  color: var(--color-text-primary);
  font-size: 0.95em;
  cursor: pointer;
  outline: none;
  transition: border-color 0.3s, box-shadow 0.3s;
  width: 100%;
  box-sizing: border-box;
}

.custom-select select:hover {
  border-color: var(--color-primary-light);
}

.custom-select select:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
  /* 聚焦光晕 */
}


.select-arrow {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 5px solid var(--color-text-secondary);
  pointer-events: none;
}

.manual-update-btn {
  background-color: var(--color-primary);
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 1em;
  transition: background-color 0.3s, box-shadow 0.3s;
  align-self: flex-start;
  /* 按钮靠左 */
}

.manual-update-btn:hover {
  background-color: var(--color-primary-light);
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
}

.manual-update-btn:active {
  background-color: #3080DD;
  /* 点击时更深色 */
}

/* 响应式设计 */
@media (max-width: 1200px) {
  #modern-dashboard {
    padding: 15px;
  }

  .dashboard-main {
    grid-template-columns: 1fr;
  }

  .left-panel,
  .right-panel {
    grid-column: 1 / -1;
  }

  .dashboard-header {
    flex-direction: column;
    gap: 15px;
    padding: 15px;
  }

  .header-right {
    flex-direction: column;
    gap: 10px;
    width: 100%;
    align-items: center;
  }

  .update-info,
  .auto-update-toggle {
    justify-content: center;
    width: 100%;
  }

  .control-group {
    flex-direction: column;
    align-items: flex-start;
  }

  .custom-select {
    width: 100%;
  }

  .manual-update-btn {
    width: 100%;
  }
}

@media (max-width: 768px) {
  .card-title {
    font-size: 1.3em;
  }

  .metric-value {
    font-size: 1.8em;
  }

  .metrics-grid {
    grid-template-columns: 1fr;
  }

  .system-time {
    font-size: 1.2em;
  }

  .alerts-list {
    font-size: 0.85em;
  }
}

@media (max-width: 480px) {
  .metric-value {
    font-size: 1.6em;
  }

  .metric-label {
    font-size: 0.8em;
  }

  .alert-item {
    font-size: 0.8em;
    padding: 8px 10px;
  }
}
</style>